#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @project: fastapi-common
# @Author : luzhiheng
# @Date : 2020/10/23
# All Depends
from typing import Generator

from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jose import jwt
from pydantic import ValidationError
from sqlalchemy.orm import Session
from starlette import status

from fastapi_common.core import security
from fastapi_common.core.config import settings
from fastapi_common.db.session import SessionLocal
from fastapi_common import models
from fastapi_common import crud


def get_db() -> Generator:
    """
        获取数据库Session 几乎大部分Api都需要Depends
    """
    try:
        db: Session = SessionLocal()
        yield db
    finally:
        db.close()


reusable_oauth2 = OAuth2PasswordBearer(
    tokenUrl=f"{settings.API_V1_STR}/user/login/access-token"
)


def get_token_payload(
        token: str = Depends(reusable_oauth2)
) -> dict:
    try:
        payload = jwt.decode(
            token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
        )
        sub_payload = payload['sub']
        return eval(sub_payload)
    except (jwt.JWTError, ValidationError):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Could not validate credentials",
        )


def get_current_role_id(
        payload: dict = Depends(get_token_payload)
) -> int:
    user_id = payload['role_id']
    return user_id


def get_current_user_id(
        payload: dict = Depends(get_token_payload)
) -> int:
    user_id = payload['user_id']
    return user_id


def get_current_user(
        db: Session = Depends(get_db),
        user_id: int = Depends(get_current_user_id)
) -> models.User:
    """
        根据request token 获取用户信息，
    """
    user = crud.user.get(db, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user


def get_current_active_user(
    current_user: models.User = Depends(get_current_user),
) -> models.User:
    if not crud.user.is_active(current_user):
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user


def get_current_active_superuser(
    current_user: models.User = Depends(get_current_user),
) -> models.User:
    if not crud.user.is_superuser(current_user):
        raise HTTPException(
            status_code=400, detail="The user doesn't have enough privileges"
        )
    return current_user

